// reflexion.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <marusdefs.h>
#include <crtdbg.h>
#include <cassert>
#include <typeinfo.h>

#ifndef _STRINGIZE
#define __STRINGIZE(val) #val
#define _STRINGIZE(val) __STRINGIZE(val)
#endif

#define __WFILE__ WIDEN(__FILE__)

#ifdef UNICODE
#define __TFILE__   __WFILE__
#else
#define __TFILE__   __FILE__
#endif

#define CODEPOINT __FILE__ "("_STRINGIZE(__LINE__)") : "

#define CTWARN(msg, param) __pragma(message(CODEPOINT "warning DEV: [" msg "] " param))
#define CTERROR(msg, param)__pragma(message(CODEPOINT "error DEV: [" msg "] " param))

#define X(name_) name_ ## _

#define     DECLARE_NAMED_STRING(name_, value_) struct name_ {\
    inline operator const char* () const { return value_;} \
    inline operator const wchar_t* () const { return L ## value_;}\
    }

#define     IMPLEMENT_NAMED_STRING(name_, value_) static DECLARE_NAMED_STRING(__ ## name_, value_) X(name_);

#define     ADD_LEX_(name_, value_)  IMPLEMENT_NAMED_STRING(name_, value_)

#define     ADD_LEX(name_)    ADD_LEX_(name_, _STRINGIZE(name_))

namespace  Lexicon {
    namespace Basic {
    ADD_LEX_(STRING, "String")
    ADD_LEX_(MEMO, "Memo")
    ADD_LEX(single)
    ADD_LEX(class)
    ADD_LEX_(namespace, "namespace")
    }
};


template <typename T>
class   TypeId {
public:
    const char* name()
    {
        _STATIC_ASSERT(0);
        CTERROR("rtti", "template<> class TypeId<T> hasn't been instantiated (see compiler output above).")
        return 0;
    }
};

using namespace Lexicon::Basic;

#define DECLARE_NATIVE_TYPE_(Type, Name) template<> class TypeId<Type> {\
protected:\
    DECLARE_NAMED_STRING(_my_name, Name);\
    static inline const _my_name& _name() {\
        static _my_name r;\
        return r;\
    }\
public:\
    typedef Type type;\
    typedef TypeId<type>    _Myt;\
    static inline const type_info& get_typeid() {\
        static const type_info& ti(typeid(type));\
        return ti;\
    }\
    static inline bool is(const type_info& ti_) {\
        return get_typeid()==ti_;\
    }\
    static inline const _my_name& name() {\
        return _name();\
    }\
    static inline size_t size() {\
        return sizeof(type);\
    }\
private:\
    TypeId<Type>();\
    TypeId<Type>(const _Myt&);\
    TypeId<Type>& operator=(const _Myt&);\
};

//    template <typename Type> friend const _Myt& typeof<Type>();\

template<typename T>
inline bool operator==(const TypeId<T>& , const type_info& right_) {
    return TypeId<T>::is(right_);
}

template<typename T>
inline bool operator==(const type_info& left_, const TypeId<T>& ) {
    return TypeId<T>::is(left_);
}

template<typename T>
inline bool operator!=(const TypeId<T>& , const type_info& right_) {
    return !TypeId<T>::is(right_);
}

template<typename T>
inline bool operator!=(const type_info& left_, const TypeId<T>& ) {
    return !TypeId<T>::is(left_);
}

template <typename T>
static inline const TypeId<T>& typeof() {
    return *(TypeId<T>*)0;
}

template <typename T>
static inline const TypeId<T>& typeof(T&) {
    return (typeof<T>());
}

template <typename T>
static inline const TypeId<T>& typeof(const T&) {
    return (typeof<T>());
}

DECLARE_NATIVE_TYPE_(char, "char")
DECLARE_NATIVE_TYPE_(signed char, "signed char")
DECLARE_NATIVE_TYPE_(unsigned char, "unsigned char")
DECLARE_NATIVE_TYPE_(wchar_t, "wchar_t")
DECLARE_NATIVE_TYPE_(signed short, "short")
DECLARE_NATIVE_TYPE_(unsigned short, "unsigned short")
DECLARE_NATIVE_TYPE_(signed int, "int")
DECLARE_NATIVE_TYPE_(unsigned int, "unsigned int")

template <typename T>
class   Iterator {
public:
    typedef typename T DataT;

    virtual bool    hasNext() const = 0;
    virtual DataT   next() = 0;   
};

template <typename _Elem = TCHAR>
class   CharIterator : public Iterator<_Elem>
{
protected:
    const DataT*  _data;
    size_t  _pos;
public:
    CharIterator(const DataT* data_)
        : _data(data_)
        , _pos(0)
    {}

    bool hasNext() const {
        return _data && _data[_pos]?true : false;
    }

    DataT   next() {
        _ASSERT(_data);
        _ASSERT(_data[_pos]);
        return _data[_pos++];
    }

};

template<typename T>
class Iterable {
public:
    virtual Iterator<T> iterator() = 0;
};


#include <iostream>
#define $ _STD cout
#define $W _STD wcout
#define $_ _STD endl
#include <errno.h>
#include <stdexcept>


class   Timestamp
{
protected:
    __int64     _time;
public:
    static const unsigned __int64 epoch = 0x019DB1DED53E8000;
    Timestamp()
        : _time(now())
    {
    }
    
    Timestamp(__int64 time_)
        : _time(time_)
    {
    }
    static __int64 now()
    {
        union {
            FILETIME ft;
            __int64  ts;
        } tmp; 
        ::GetSystemTimeAsFileTime(&tmp.ft);
	    return (tmp.ts -= epoch)/ 10;
    }

    operator __int64 () const 
    {
        return _time;
    }
};

typedef const void*     CpuReg;
typedef DWORD           ThreadId;

// returns HMODULE of the module the CodeSeg ptr p belongs to
extern "C" HMODULE  GetCodeModuleHandle(CpuReg p)
{
    MEMORY_BASIC_INFORMATION mbi;
    return((VirtualQuery(p, &mbi, sizeof(mbi)) != 0) 
        ? (HMODULE) mbi.AllocationBase : NULL);
}

class exec_point
{
protected:
    CpuReg      _eip;
    ThreadId    _thread_id;
    Timestamp   _time;

public:


    exec_point(CpuReg eip_ = ::Inl::getEIP())
        : _eip(eip_)
        , _thread_id(::GetCurrentThreadId())
    {}

    exec_point(const exec_point& rh_)
        : _eip(rh_._eip)
        , _thread_id(rh_._thread_id)
        , _time(rh_._time)
    {}

    exec_point& operator=(const exec_point& rh_)
    {
        _eip = rh_._eip;
        _thread_id = rh_._thread_id;
        _time = rh_._time;
        return *this;
    }

    inline  CpuReg eip() const 
    {
        return _eip;
    }

    inline  ThreadId    thread_id() const
    {
        return _thread_id;
    }
};

class code_point
{
protected:

    static const char* unknown_file()
    {
        static char result [] = "<unknown>";
        return result;
    }
    int _line;
    const char* _file;
    exec_point  _ep;
public:
    code_point(const exec_point& ep_ = exec_point())
        : _line(0)
        , _file(unknown_file())
        , _ep(ep_)
    {}

    code_point(int line_, const char* file_, const exec_point& ep_ = exec_point())
        : _line(line_)
        , _file(file_)
        , _ep(ep_)
    {}

    code_point(const code_point& rh_)
        : _line(rh_._line)
        , _file(rh_._file)
        , _ep(rh_._ep)
    {}

    code_point& operator = (const code_point& rh_) 
    {
        _line = rh_._line;
        _file = rh_._file;
        _ep   = rh_._ep;
        return *this;
    }

    int line() const
    {
        return _line;
    }
    const char* file() const
    {
        return _file;
    }
    const exec_point&   ep() const
    {
        return _ep;
    }

    _STD string dump() const
    {
        return "TODO: implement code_point::dump()";
    }
};


#define LINKAGE 

template <typename T>
class   cloneable
{
public:
    virtual T*  clone() const = 0;
};

template <typename T>
class   clone_ptr
{
public:
    typedef clone_ptr<T>    _Myt;
    typedef cloneable<T>    _Type;

    _Myt()
        : _clone(0)
    {}

    _Myt(const _Type&   rh_)
        : _clone(rh_.clone())
    { }

    _Myt(const _Myt& rh_)
        : _clone(rh_.clone())
    { }

    _Myt&  operator=(const _Type& rh_)
    {
        set(rh_.clone());
        return *this;
    }

    _Myt&  operator=(const _Myt& rh_)
    {
        set(rh_.clone());
        return *this;
    }

    ~clone_ptr<T>()
    {
        set(0);
    }

    inline T* get()  const
    {
        return static_cast<T*>(_clone);
    }

    inline T* clone() const 
    {
        return _clone == 0? 0 : _clone->clone();
    }

protected:
    inline  void    set(_Type* new_) 
    {
        if (_clone != 0 && _clone != new_)
            delete get();
        _clone = new_;
    }

    _Type*  _clone;
};

#if 0
typedef _STDEXT exception std_exception;
#else
typedef _STD exception std_exception;
#endif

class Exception : public std_exception
                , public cloneable<Exception>
	/// This is the base class for all exceptions defined
	/// in library.
{
public:
    typedef std_exception _Base;
    typedef clone_ptr<Exception>    nested_ptr;

private:
	_STD string _what;
    nested_ptr  _nested;
    code_point  _cp;
	int			_code;

protected:
	/// Standard constructor.
    Exception()
        : _Base()
        , _code(0)
    {
        $ << "[Exception()]"<< ((const void*) this) << $_; 
    }

public:
    Exception(const char* msg_)
        : _Base()
        , _what(msg_)
        , _code(0)
    {
        $ << "[Exception(const char* msg_)]"<< ((const void*) this) << $_; 
    }

	// Creates an exception and stores a clone
	// of the nested exception.
    Exception(const char* msg_, const Exception& nested_)
        : _Base()
        , _what(msg_)
        , _nested(nested_)
        , _code(0)
    {
        $ << "[Exception(const char* msg_, const Exception& nested_)]"<< ((const void*) this) << " with nested " << ((const void*)&nested_) << $_; 
    }

	/// Copy constructor.
    Exception(const Exception& rh_)
        : _Base(rh_)
        , _what(rh_._what)
        , _nested(rh_._nested)
        , _cp(rh_._cp)
        , _code(rh_._code)
    {
        $ << "[Exception(const Exception& rh_)] clone "<< ((const void*) this) << " of " << ((const void*)&rh_) << $_; 
    }

    explicit Exception(const _Base& rh_)
        : _Base(rh_)
        , _what(rh_.what())
        , _code(0)
    {
        $ << "[explicit Exception(const _Base& rh_)]"<< ((const void*) this) << $_; 
    }
	
    virtual ~Exception() throw()
    {
        $ << "[virtual ~Exception()]"<< ((const void*) this) << $_; 
    }


	/// Assignment operator.
    Exception& operator = (const Exception& rh_)
    {
	    if (&rh_ != this)
        {   
            _Base::operator=(rh_);
		    _what   = rh_._what;
            _nested = rh_._nested;
            _cp     = rh_._cp;
		    _code   = rh_._code;
	    }
	    return *this;
    }

	/// Sets the message for the exception.
	inline Exception& message(const char* msg)
    {
	    _what = msg;
        return *this;
    }

	/// Sets the code point for the exception.
    inline Exception&  codePoint(int line_, const char* file_)
    {
        _cp = code_point(line_, file_);
        return *this;
    }

	inline const Exception* nested() const 
    {
        return static_cast<const Exception*>(_nested.get());
    }
			
    /// Returns a string consisting of the
    /// message name and the message text.
    std::string displayText() const
    {
	    std::string txt;
        if (_cp.line() != 0)
        {
            txt.append(_cp.file());
            char _buf[10];
            _itoa_s(_cp.line(), _buf, 10);
            txt.append("(");
            txt.append(_buf);
            txt.append(") ");
        }

	    txt.append(": ");
	    txt.append(what());

	    return txt;
    }

    // Returns the reason of the exception
    virtual const char* __CLR_OR_THIS_CALL what() const throw()
    {
        return _what.c_str();
    }

    /// Raises the exception.
    virtual void raise() const = 0;
};

typedef Exception EXCEPTION_BASE;

class   StdException : public EXCEPTION_BASE
{
public:
    explicit StdException(const std_exception& rh_)
        : EXCEPTION_BASE(rh_)
    {}

    StdException(const StdException& exc) 
        : EXCEPTION_BASE (exc) 
    {}

    ~StdException() throw() 
    {}

    StdException& operator = (const StdException& rh_) 
    { 
        EXCEPTION_BASE::operator=(rh_); 
        return *this; 
    }
    EXCEPTION_BASE* clone() const 
    { 
        return new StdException(*this); 
    }

    const char* name() const throw() 
    { 
        return typeid(*this).name(); 
    }

    void raise() const 
    { 
        _RAISE( *this ); 
    }	
protected:
    _STD string _what;
};
//
// Macros for quickly declaring and implementing exception classes.
// Unfortunately, we cannot use a template here because character
// pointers (which we need for specifying the exception name)
// are not allowed as template arguments.
//
#define DECLARE_EXCEPTION(CLS, BASE, WHAT) \
	class CLS: public BASE \
	{ \
	public: \
    CLS() : BASE() {} \
    CLS(const char* msg) : BASE(msg) {} \
    CLS(const char* msg, const EXCEPTION_BASE& exc): BASE(msg, exc) {}	\
    CLS(const CLS& exc) : BASE (exc) {} \
    ~CLS() throw() {} \
    CLS& operator = (const CLS& rh_) { BASE::operator=(rh_); return *this; } \
    EXCEPTION_BASE* clone() const { return new CLS(*this); } \
    const char* what() const throw() { return (WHAT); } \
    void raise() const { _RAISE( *this ); }	\
	};


//
// Standard exception classes
//
DECLARE_EXCEPTION(LogicException, Exception, "Logic exception")
DECLARE_EXCEPTION(AssertionViolationException, LogicException, "Assertion violation")
DECLARE_EXCEPTION(NullPointerException, LogicException, "Null pointer")
DECLARE_EXCEPTION(NullValueException, LogicException, "Null value")
DECLARE_EXCEPTION(BugcheckException, LogicException, "Bugcheck")
DECLARE_EXCEPTION(InvalidArgumentException, LogicException, "Invalid argument")
DECLARE_EXCEPTION(NotImplementedException, LogicException, "Not implemented")
DECLARE_EXCEPTION(RangeException, LogicException, "Out of range")
DECLARE_EXCEPTION(IllegalStateException, LogicException, "Illegal state")
DECLARE_EXCEPTION(InvalidAccessException, LogicException, "Invalid access")
DECLARE_EXCEPTION(SignalException, LogicException, "Signal received")
DECLARE_EXCEPTION(UnhandledException, LogicException, "Unhandled exception")

DECLARE_EXCEPTION(RuntimeException, Exception, "Runtime exception")
DECLARE_EXCEPTION(NotFoundException, RuntimeException, "Not found")
DECLARE_EXCEPTION(ExistsException, RuntimeException, "Exists")
DECLARE_EXCEPTION(TimeoutException, RuntimeException, "Timeout")
DECLARE_EXCEPTION(SystemException, RuntimeException, "System exception")
DECLARE_EXCEPTION(RegularExpressionException, RuntimeException, "Error in regular expression")
DECLARE_EXCEPTION(LibraryLoadException, RuntimeException, "Cannot load library")
DECLARE_EXCEPTION(LibraryAlreadyLoadedException, RuntimeException, "Library already loaded")
DECLARE_EXCEPTION(NoThreadAvailableException, RuntimeException, "No thread available")
DECLARE_EXCEPTION(PropertyNotSupportedException, RuntimeException, "Property not supported")
DECLARE_EXCEPTION(PoolOverflowException, RuntimeException, "Pool overflow")
DECLARE_EXCEPTION(NoPermissionException, RuntimeException, "No permission")
DECLARE_EXCEPTION(OutOfMemoryException, RuntimeException, "Out of memory")
DECLARE_EXCEPTION(DataException, RuntimeException, "Data error")

DECLARE_EXCEPTION(DataFormatException, DataException, "Bad data format")
DECLARE_EXCEPTION(SyntaxException, DataException, "Syntax error")
DECLARE_EXCEPTION(CircularReferenceException, DataException, "Circular reference")
DECLARE_EXCEPTION(PathSyntaxException, SyntaxException, "Bad path syntax")
DECLARE_EXCEPTION(IOException, RuntimeException, "I/O error")
DECLARE_EXCEPTION(ProtocolException, IOException, "Protocol error")
LINKAGE DECLARE_EXCEPTION(FileException, IOException, "File access error")
DECLARE_EXCEPTION(FileExistsException, FileException, "File exists")
DECLARE_EXCEPTION(FileNotFoundException, FileException, "File not found")
DECLARE_EXCEPTION(PathNotFoundException, FileException, "Path not found")
DECLARE_EXCEPTION(FileReadOnlyException, FileException, "File is read-only")
DECLARE_EXCEPTION(FileAccessDeniedException, FileException, "Access to file denied")
DECLARE_EXCEPTION(CreateFileException, FileException, "Cannot create file")
DECLARE_EXCEPTION(OpenFileException, FileException, "Cannot open file")
DECLARE_EXCEPTION(WriteFileException, FileException, "Cannot write file")
DECLARE_EXCEPTION(ReadFileException, FileException, "Cannot read file")
DECLARE_EXCEPTION(UnknownURISchemeException, RuntimeException, "Unknown URI scheme")

DECLARE_EXCEPTION(ApplicationException, Exception, "Application exception")
DECLARE_EXCEPTION(BadCastException, RuntimeException, "Bad cast exception")

inline void RaiseException(Exception& ex, int line_, const char* file_)
{
    ex.codePoint(line_, file_).raise();
}

#define RAISE(ex)   RaiseException(ex, __LINE__, __FILE__)


int _tmain(int argc, _TCHAR* argv[])
{
    char c;
    unsigned short s;
    signed __int32 a;
    $ << typeid(char).raw_name() << $_;
    $ << typeid(signed char).raw_name() << $_;
    $ << typeid(unsigned char).raw_name() << $_;
    $ << typeid(int).name() << $_;
    $ << typeid(signed int).name() << $_;
    $ << typeid(signed __int32).name() << $_;
    $ << typeid(ULONG_PTR).name() << $_;

    if (typeid(int) != typeof(a)) {
        $ << "OK!" << $_;
    } else {
        $ << "BAD!" << $_;
    }
    //const _STD type_info ti = typeid(_STD cout);
    CharIterator<char> ci(typeid(s).raw_name());
    CpuReg eip = ::Inl::getEIP();
    $ << eip << $_;
    while(ci.hasNext())
        _STD cout << ci.next();
    $ << $_;

    $ << TypeId<int>::get_typeid().raw_name() << $_;
    $ << typeof(c).name() << $_;
    $ << typeof(s).name() << $_;
    $ << typeof(a).name() << $_;
    $ << TypeId<TCHAR>::name() << $_;
    $W << (LPCTSTR)MEMO_ << $_;

    try {
        try {
            //_RAISE(std::bad_cast());
            //_RAISE(_STD underflow_error("underflow error"));
            //RAISE(StdException(_STD underflow_error("underflow error")));
            RAISE(FileAccessDeniedException());
        } catch (const Exception& ex_) {
            //$ << ex_.displayText().c_str() << $_;
            RAISE(LogicException("Exception thrown", ex_).message("See nested exceptions."));
        } catch (_STD exception& ex_) {
            RAISE(LogicException("STD Exception thrown", StdException(ex_)));
        }
    } catch(const Exception& ex_) {
        $ << ex_.displayText().c_str() << $_;
        const Exception* next = ex_.nested();
        while(next)
        {
            $ << ">>>" << next->displayText().c_str() << $_;
            next = next->nested(); 
        }
    }


	return 0;
}

